﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Transactions;
using WCS.Infrastructure.Attr;
using WCS.Infrastructure.Dto.Request.Divided;
using WCS.Infrastructure.Dto.Request.Log;
using WCS.Infrastructure.Dto.Request.Payment;
using WCS.Infrastructure.Dto.Response.Common;
using WCS.Infrastructure.Dto.Response.Payment;
using WCS.Infrastructure.EFCore;
using WCS.Infrastructure.IOC;
using WCS.Infrastructure.Tools;
using WCS.Repository.Interface;
using WCS.Service.Interface;

namespace WCS.Service.Instance
{
    [Inject]
    public class DividedService : BaseService, WCS.Service.Interface.IDividedService
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IConfiguration _configuration;
        private readonly ILogService _logService;
        private readonly IUserService _userService;
        private readonly DividedIOC _dividedIOC;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IPaymentService _paymentService;
        public DividedService(IConfiguration configuration, ILogService logService, IUnitOfWork unitOfWork, IUserService userService,
            DividedIOC dividedIOC, IHttpContextAccessor httpContextAccessor, IPaymentService paymentService)
        {
            _configuration = configuration;
            _logService = logService;
            _unitOfWork = unitOfWork;
            _userService = userService;
            _dividedIOC = dividedIOC;
            _httpContextAccessor = httpContextAccessor;
            _paymentService = paymentService;
        }


        /// <summary>
        /// 在分账协议里面批量设置收款码（该协议下的收款码列表与目标集合对齐）
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> SetDividedAgreementPaymentCodesAsync(SetDividedAgreementPaymentCodesRequestDto dto)
        {
            try
            {
                if (string.IsNullOrEmpty(dto.DividedAgreementId))
                    return GetResult(message: "参数错误：分账协议ID不能为空");

                var txOptions = new System.Transactions.TransactionOptions
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
                    Timeout = TimeSpan.FromMinutes(2)
                };
                using var scope = new TransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled);

                // 校验协议
                var agreement = await _dividedIOC._dividedAgreementEFCore
                    .QueryAll(d => d.Id == dto.DividedAgreementId && d.IsDeleted == false)
                    .FirstOrDefaultAsync();

                if (agreement == null)
                    return GetResult(message: "找不到分账协议，请稍后重试！");

                if (!IsAgreementEffective(agreement, DateTime.Now))
                {
                    return GetResult(message: "该分账协议无效（未激活/未启用或不在有效期）");
                }

                // 入参 MerchantId 校验（如传入）
                if (!string.IsNullOrEmpty(dto.MerchantId) &&
                    !string.Equals(dto.MerchantId, agreement.MerchantId, StringComparison.OrdinalIgnoreCase))
                    return GetResult(message: "参数错误：商户不匹配");

                var targetIds = (dto.PaymentCodeIds ?? new List<string>()).Distinct().ToList();

                // 当前该协议下的收款码
                var currentIds = await _dividedIOC._paymentCodeEFCore
                    .QueryAll(d => d.MerchantId == agreement.MerchantId && d.DividedAgreementId == agreement.Id)
                    .Select(d => d.Id)
                    .ToListAsync();

                var toUnbindIds = currentIds.Except(targetIds).ToList();
                var toBindIds = targetIds.Except(currentIds).ToList();

                int affected = 0;

                // 解绑：清空 DividedAgreementId（限定在该协议与商户下）
                if (toUnbindIds.Count > 0)
                {
                    var unbindList = await _dividedIOC._paymentCodeEFCore
                        .QueryAll(d => toUnbindIds.Contains(d.Id)
                                       && d.MerchantId == agreement.MerchantId
                                       && d.DividedAgreementId == agreement.Id)
                        .ToListAsync();

                    foreach (var code in unbindList)
                    {
                        code.DividedAgreementId = null;
                        code.LastModificationTime = DateTime.Now;
                        code.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                    }

                    if (unbindList.Count > 0)
                    {
                        await _dividedIOC._paymentCodeEFCore.UpdateRangeAsync(unbindList);
                        affected += await _dividedIOC._paymentCodeEFCore.SaveChangesAsync();
                    }
                }

                // 绑定：设置 DividedAgreementId（限定商户一致）
                if (toBindIds.Count > 0)
                {
                    var bindList = await _dividedIOC._paymentCodeEFCore
                        .QueryAll(d => toBindIds.Contains(d.Id)
                                       && d.MerchantId == agreement.MerchantId)
                        .ToListAsync();

                    foreach (var code in bindList)
                    {
                        code.DividedAgreementId = agreement.Id;
                        code.LastModificationTime = DateTime.Now;
                        code.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                    }

                    if (bindList.Count > 0)
                    {
                        await _dividedIOC._paymentCodeEFCore.UpdateRangeAsync(bindList);
                        affected += await _dividedIOC._paymentCodeEFCore.SaveChangesAsync();
                    }
                }

                if (affected == 0)
                    return GetResult(message: "批量设置收款码失败，请稍后重试！");

                scope.Complete();
                return GetResult(affected);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 新增分账协议
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddDividedAgreementAsync(DividedAgreementRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);
                string dividedAgreementId = Config.GUID();

                // 子协议校验与父明细绑定前置校验
                if (!string.IsNullOrEmpty(dto.ParentAgreementId))
                {
                    // 1) 校验父协议存在且为顶层
                    var parent = await _dividedIOC._dividedAgreementEFCore
                        .QueryAll(d => d.Id == dto.ParentAgreementId && d.IsDeleted == false && d.EnableStatus == 1)
                        .FirstOrDefaultAsync();
                    if (parent == null)
                        return GetResult(message: "父协议不存在或已删除！");
                    //if (!string.IsNullOrEmpty(parent.ParentAgreementId))
                    //    return GetResult(message: "不允许在子协议下继续创建子协议！");

                    // 2) 商户一致性校验（如传入 MerchantId）
                    //if (!string.IsNullOrEmpty(dto.MerchantId) && !string.Equals(parent.MerchantId, dto.MerchantId, StringComparison.OrdinalIgnoreCase))
                    //    return GetResult(message: "商户不一致，无法创建子协议！");

                    // 3) 当前登录用户必须在父协议的分账详情中（用于绑定 SubAgreementId）
                    var currentUserId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                    if (string.IsNullOrEmpty(currentUserId))
                        return GetResult(message: "当前登录用户不存在，无法创建子协议！");

                    var parentDetailCheck = await _dividedIOC._dividedAgreementDetailEFCore
                        .QueryAll(d => d.DividedAgreementId == parent.Id && d.UserId == currentUserId)
                        .FirstOrDefaultAsync();
                    if (parentDetailCheck == null)
                        return GetResult(message: "未找到父协议的当前用户分账详情！");
                    if (!string.IsNullOrEmpty(parentDetailCheck.SubAgreementId))
                        return GetResult(message: "该父协议分账详情已绑定子协议，不能重复创建！");

                    // 成环校验：准备绑定 parent -> newChild
                    var willCycle = await WouldCreateCycleWhenBindingAsync(dto.ParentAgreementId, dividedAgreementId);
                    if (willCycle)
                        return GetResult(message: "父子绑定将产生环，请调整分账关系！");

                    // 4) 子协议时间范围校验/收敛到父协议区间
                    //var reqStart = (DateTime)dto.StartTime;
                    //var reqEnd = dto.EndTime;
                    //if (reqStart < parent.StartTime)
                    //    return GetResult(message: "子协议开始时间不能早于父协议开始时间！");
                    //if (parent.EndTime.HasValue)
                    //{
                    //    if (reqEnd == null || reqEnd > parent.EndTime)
                    //        dto.EndTime = parent.EndTime; // 收敛到父协议的结束时间
                    //}
                }

                DividedAgreement dividedAgreement = new DividedAgreement()
                {
                    Id = dividedAgreementId,
                    AgreementCode = Config.GenerateCode(),
                    AgreementName = dto.AgreementName,
                    MerchantId = dto.MerchantId,
                    DividedCycle = dto.DividedCycle,
                    StartTime = (DateTime)dto.StartTime,
                    EndTime = dto.EndTime,
                    CreationTime = DateTime.Now,
                    IsDeleted = false,
                    EnableStatus = 0,
                    ActivationStatus = 1,
                    CreatorId = dto.CreatorId ?? _httpContextAccessor.HttpContext?.GetCurrentUserId(),
                    ParentAgreementId = dto.ParentAgreementId
                };

                var merchant = await _dividedIOC._merchantEFCore.QueryAll(d => d.Id == dto.MerchantId).FirstOrDefaultAsync();
                var user = await _dividedIOC._sysUserEFCore.QueryAll(d => d.Id == merchant.CreatorId).FirstOrDefaultAsync();
                var userRole = await _dividedIOC._sysUserRoleEFCore.QueryAll(d => d.UserId == merchant.CreatorId && d.MerchantId == merchant.Id).FirstOrDefaultAsync();
                DividedAgreementDetail dividedAgreementDetail = new DividedAgreementDetail()
                {
                    Id = Config.GUID(),
                    DividedAgreementId = dividedAgreementId,
                    CreationTime = DateTime.Now,
                    Ratio = 1,
                    UserId = merchant.CreatorId,
                    IsMasterAccount = true, //默认商户创建人是主账户
                    ActivationStatus = 1, //主账户默认激活
                    UserRoleId = userRole.Id,
                };

                await _dividedIOC._dividedAgreementEFCore.AddAsync(dividedAgreement);
                var dividedAgreementResult = await _dividedIOC._dividedAgreementEFCore.SaveChangesAsync();
                if (dividedAgreementResult == 0)
                    return GetResult(message: "新增分账协议失败，请稍后重试！");

                await _dividedIOC._dividedAgreementDetailEFCore.AddAsync(dividedAgreementDetail);
                var dividedAgreementDetailResult = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();
                if (dividedAgreementDetailResult == 0)
                    return GetResult(message: "新增分账协议详情失败，请稍后重试！");

                // 5) 绑定父明细的 SubAgreementId（若为子协议场景）并持久化
                if (!string.IsNullOrEmpty(dto.ParentAgreementId))
                {
                    var currentUserId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                    var parentDetail = await _dividedIOC._dividedAgreementDetailEFCore
                        .QueryAll(d => d.DividedAgreementId == dto.ParentAgreementId && d.UserId == currentUserId)
                        .FirstOrDefaultAsync();
                    if (parentDetail == null)
                        return GetResult(message: "未找到父协议的当前用户分账详情！");

                    // 8) 回写父明细 SubAgreementId（先校验是否已有父协议、再校验成环）
                    var conflictParentId = await FindExistingParentAgreementIdAsync(dividedAgreementId);
                    if (!string.IsNullOrEmpty(conflictParentId))
                        return GetResult(message: $"该子协议已绑定到父协议（{conflictParentId}），不允许重复绑定！");

                    // 环路校验：若绑定会形成循环，则拒绝
                    var wouldCycle = await WouldCreateCycleWhenBindingAsync(dto.ParentAgreementId, dividedAgreementId);
                    if (wouldCycle)
                        return GetResult(message: "绑定父协议详情失败：该绑定会形成循环关联！");

                    parentDetail.SubAgreementId = dividedAgreementId;
                    await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(parentDetail);
                    var affected = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();
                    if (affected == 0)
                        return GetResult(message: "绑定父协议详情失败，请稍后重试！");
                }

                scope.Complete();
                return GetResult(1, data: dividedAgreementId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取分账协议列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedAgreementListAsync(DividedAgreementRequestDto dto)  
        {
            var data = await _dividedIOC._dividedAgreementEFCore.QueryAll(out int total, dto.Page, dto.Limit,
                d => (string.IsNullOrEmpty(dto.Key) || d.AgreementName.Contains(dto.Key))
                && (string.IsNullOrEmpty(dto.MerchantId) || d.MerchantId.Contains(dto.MerchantId))
                && (dto.EnableStatus == -1 || d.EnableStatus == dto.EnableStatus)
                && (dto.ActivationStatus == -1 || d.ActivationStatus == dto.ActivationStatus)
                && d.IsDeleted == false,
                d => d.CreationTime, false)
                .Select(d => new DividedAgreementRequestDto
                {
                    Id = d.Id,
                    AgreementCode = d.AgreementCode,
                    AgreementName = d.AgreementName,
                    CreationTime = d.CreationTime,
                    IsDeleted = d.IsDeleted,
                    EnableStatus = d.EnableStatus,
                    ActivationStatus = d.ActivationStatus,
                    ParentAgreementId = d.ParentAgreementId
                }).ToListAsync();

            return GetResult(1, data: new { data, total });
        }

        /// <summary>
        /// 获取单个分账协议详细信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedAgreementAsync(string id)
        {
            var data = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == id).Select(d => new DividedAgreementRequestDto
            {
                Id = d.Id,
                AgreementCode = d.AgreementCode,
                AgreementName = d.AgreementName,
                StartTime = d.StartTime,
                EndTime = d.EndTime,
                DividedCycle = d.DividedCycle,
                MerchantId = d.MerchantId,
                CreationTime = d.CreationTime,
                CreatorId = d.CreatorId,
                LastModificationTime = d.LastModificationTime,
                LastModifierId = d.LastModifierId,
                IsDeleted = d.IsDeleted,
                EnableStatus = d.EnableStatus,
                ActivationStatus = d.ActivationStatus,
                ParentAgreementId = d.ParentAgreementId,
            }).FirstOrDefaultAsync();

            if (data == null)
                return GetResult(message: "找不到此分账协议，请稍后重试！");

            var paymentCodes = await _dividedIOC._paymentCodeEFCore.QueryAll(d => d.DividedAgreementId == data.Id).ToListAsync();
            data.CodeIds = paymentCodes.Select(d => d.Id).ToList();
            data.CodeNames = paymentCodes.Select(d => d.CodeName).ToList();

            if (!string.IsNullOrEmpty(data.CreatorId))
                data.CreatorName = await _dividedIOC._sysUserRoleEFCore.QueryAll(d => d.UserId == data.CreatorId && d.MerchantId == data.MerchantId).Select(d => d.Name).FirstOrDefaultAsync();
            if (!string.IsNullOrEmpty(data.LastModifierId))
                data.LastModifierName = await _dividedIOC._sysUserRoleEFCore.QueryAll(d => d.UserId == data.LastModifierId && d.MerchantId == data.MerchantId).Select(d => d.Name).FirstOrDefaultAsync();

            return GetResult(1, data: data);
        }

        /// <summary>
        /// 编辑分账协议
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateDividedAgreementAsync(DividedAgreementRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                var data = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dto.Id).FirstOrDefaultAsync();
                if (data == null)
                {
                    return GetResult(message: "找不到此分账协议，请稍后重试");
                }

                // 记录旧父协议
                var oldParentAgreementId = data.ParentAgreementId;

                // 若清空父协议：先清理旧父明细的 SubAgreementId，再置空 ParentAgreementId
                if (string.IsNullOrEmpty(dto.ParentAgreementId))
                {
                    if (!string.IsNullOrEmpty(oldParentAgreementId))
                    {
                        await ClearParentBindingAsync(childAgreementId: data.Id, parentAgreementId: oldParentAgreementId!);
                    }

                    data.ParentAgreementId = null;
                    // 继续后续字段更新与保存
                }
                else
                {
                    if (dto.ParentAgreementId != data.ParentAgreementId)
                    {
                        // 若换绑到不同父协议：先清理旧父绑定，再执行现有绑定校验与写入
                        if (!string.IsNullOrEmpty(oldParentAgreementId) &&
                            !string.Equals(oldParentAgreementId, dto.ParentAgreementId, StringComparison.OrdinalIgnoreCase))
                        {
                            await ClearParentBindingAsync(childAgreementId: data.Id, parentAgreementId: oldParentAgreementId!);
                        }

                        // 子协议校验与父明细绑定前置校验（原有逻辑保留）
                        var parent = await _dividedIOC._dividedAgreementEFCore
                            .QueryAll(d => d.Id == dto.ParentAgreementId && d.IsDeleted == false && d.EnableStatus == 1)
                            .FirstOrDefaultAsync();
                        if (parent == null)
                            return GetResult(message: "父协议不存在或已删除！");

                        //if (!string.IsNullOrEmpty(dto.MerchantId) && !string.Equals(parent.MerchantId, dto.MerchantId, StringComparison.OrdinalIgnoreCase))
                        //    return GetResult(message: "商户不一致，无法创建子协议！");

                        var currentUserId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                        if (string.IsNullOrEmpty(currentUserId))
                            return GetResult(message: "当前登录用户不存在，无法创建子协议！");

                        var parentDetailCheck = await _dividedIOC._dividedAgreementDetailEFCore
                            .QueryAll(d => d.DividedAgreementId == parent.Id && d.UserId == currentUserId)
                            .FirstOrDefaultAsync();
                        if (parentDetailCheck == null)
                            return GetResult(message: "未找到父协议的当前用户分账详情！");
                        if (!string.IsNullOrEmpty(parentDetailCheck.SubAgreementId))
                            return GetResult(message: "该父协议分账详情已绑定子协议，不能重复创建！");

                        // 若仍检测到该子协议被其他父协议绑定（并非当前目标父协议），按换绑策略已先清理
                        var conflictParentId = await FindExistingParentAgreementIdAsync(dto.Id);
                        if (!string.IsNullOrEmpty(conflictParentId) &&
                            !string.Equals(conflictParentId, dto.ParentAgreementId, StringComparison.OrdinalIgnoreCase))
                        {
                            // 正常情况下上方已清理旧父绑定，这里只是兜底
                            await ClearParentBindingAsync(childAgreementId: dto.Id, parentAgreementId: conflictParentId!);
                        }

                        // 成环校验：准备绑定 parent -> child
                        var willCycle = await WouldCreateCycleWhenBindingAsync(dto.ParentAgreementId, dto.Id);
                        if (willCycle)
                            return GetResult(message: "父子绑定将产生环，请调整分账关系！");

                        // 绑定到目标父明细
                        var parentDetail = await _dividedIOC._dividedAgreementDetailEFCore
                            .QueryAll(d => d.DividedAgreementId == dto.ParentAgreementId && d.UserId == currentUserId)
                            .FirstOrDefaultAsync();
                        if (parentDetail == null)
                            return GetResult(message: "未找到父协议的当前用户分账详情！");

                        parentDetail.SubAgreementId = dto.Id;
                        await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(parentDetail);
                        var affected = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();
                        if (affected == 0)
                            return GetResult(message: "绑定父协议详情失败，请稍后重试！");

                        data.ParentAgreementId = dto.ParentAgreementId; // 目标父协议
                    }
                }

                data.AgreementName = dto.AgreementName;
                data.DividedCycle = dto.DividedCycle;
                data.StartTime = (DateTime)dto.StartTime;
                data.EndTime = dto.EndTime;
                data.LastModificationTime = DateTime.Now;
                data.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                //data.EnableStatus = (int)dto.EnableStatus;

                await _dividedIOC._dividedAgreementEFCore.UpdateAsync(data);
                var result = await _dividedIOC._dividedAgreementEFCore.SaveChangesAsync();

                if (dto.Ids.Count > 0)
                {
                    var codes = await _dividedIOC._paymentCodeEFCore.QueryAll(d => dto.Ids.Contains(d.Id)).ToListAsync();
                    foreach (var code in codes)
                    {
                        code.DividedAgreementId = data.Id;
                    }
                    await _dividedIOC._paymentCodeEFCore.UpdateRangeAsync(codes);
                    var codesResult = await _dividedIOC._paymentCodeEFCore.SaveChangesAsync();
                    if (codesResult == 0)
                        return GetResult(message: "设置协议绑定收款码失败，请稍后重试！");
                }

                if (result == 0)
                    return GetResult(message: "编辑分账协议信息错误，请稍后重试！");

                scope.Complete();
                return GetResult(result);
            }
            catch (Exception)
            {

                throw;
            }

        }

        /// <summary>
        /// 禁用/启用分账协议
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ApiResult> BanDividedAgreementAsync(BanDividedAgreementRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                var data = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dto.Id).FirstOrDefaultAsync();
                if (data == null)
                {
                    return GetResult(message: "找不到此分账协议，请稍后重试");
                }

                data.EnableStatus = (int)dto.EnableStatus;
                data.LastModificationTime = DateTime.Now;
                data.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();

                await _dividedIOC._dividedAgreementEFCore.UpdateAsync(data);
                var result = await _dividedIOC._dividedAgreementEFCore.SaveChangesAsync();

                if (result == 0)
                    return GetResult(message: "编辑分账协议信息错误，请稍后重试！");

                scope.Complete();
                return GetResult(result);
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 清理旧父协议的分账详情中的 SubAgreementId 绑定
        /// </summary>
        /// <param name="childAgreementId"></param>
        /// <param name="parentAgreementId"></param>
        /// <returns></returns>
        private async Task ClearParentBindingAsync(string childAgreementId, string parentAgreementId)
        {
            var parentDetail = await _dividedIOC._dividedAgreementDetailEFCore
                .QueryAll(d => d.DividedAgreementId == parentAgreementId && d.SubAgreementId == childAgreementId)
                .FirstOrDefaultAsync();

            if (parentDetail != null)
            {
                parentDetail.SubAgreementId = null;
                await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(parentDetail);
                await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 删除分账协议(软删除)
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> DeleteDividedAgreementAsync(DividedAgreementRequestDto dto)
        {

            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                var dividedAgreement = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dto.Id).FirstOrDefaultAsync();
                if (dividedAgreement == null)
                    return GetResult(message: "找不到该分账协议，请稍后重试！");
                dividedAgreement.IsDeleted = true;
                dividedAgreement.DeletionTime = DateTime.Now;
                dividedAgreement.DeleterId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                await _dividedIOC._dividedAgreementEFCore.UpdateAsync(dividedAgreement);
                var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();

                if (result == 0)
                {
                    return GetResult(message: "删除分账协议错误，请稍后重试!");
                }

                // 解绑该协议下的收款码
                var paymentCodes = await _dividedIOC._paymentCodeEFCore.QueryAll(d => d.DividedAgreementId == dividedAgreement.Id).ToListAsync();
                foreach (var code in paymentCodes)
                {
                    code.DividedAgreementId = null;
                    code.LastModificationTime = DateTime.Now;
                    code.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                }
                await _dividedIOC._paymentCodeEFCore.UpdateRangeAsync(paymentCodes);
                await _dividedIOC._paymentCodeEFCore.SaveChangesAsync();


                await ClearParentBindingAsync(childAgreementId: dividedAgreement.Id, parentAgreementId: dividedAgreement.ParentAgreementId!);
                scope.Complete();
                return GetResult(result);

            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 查询与当前用户（或指定用户）有关的分账协议列表
        /// 支持作为参与者/创建者两个维度，去重后返回
        /// </summary>
        public async Task<ApiResult> GetUserRelatedDividedAgreementsAsync(DividedAgreementUserQueryDto dto)
        {
            var currentUserId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
            var targetUserId = string.IsNullOrEmpty(dto.UserId) ? currentUserId : dto.UserId;
            if (string.IsNullOrEmpty(targetUserId))
                return GetResult(message: "未能识别目标用户！");

            // 若两个维度都不包含，直接返回空
            if (!dto.IncludeParticipation && !dto.IncludeOwned)
                return GetResult(1, data: new { data = new List<object>(), total = 0 });

            // 协议基础过滤
            var agreements = _dividedIOC._dividedAgreementEFCore.QueryAll(a =>
                a.IsDeleted == false
                && (string.IsNullOrEmpty(dto.MerchantId) || a.MerchantId == dto.MerchantId)
                && (dto.EnableStatus == -1 || a.EnableStatus == dto.EnableStatus)
                && (dto.ActivationStatus == -1 || a.ActivationStatus == dto.ActivationStatus)
                && (!dto.OnlySubAgreements || a.ParentAgreementId != null)
            );

            // 当前用户在明细中的过滤（可选：排除已绑定子协议的明细）
            var userDetails = _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => d.UserId == targetUserId
                && (!dto.OnlyMyDetailsWithoutSubAgreement || string.IsNullOrEmpty(d.SubAgreementId))
                );

            // 当开关为真时，外层协议也跟随明细过滤，仅保留包含这些明细的协议
            if (dto.OnlyMyDetailsWithoutSubAgreement)
            {
                var detailAgreementIds = userDetails.Select(d => d.DividedAgreementId);
                agreements = agreements.Where(a => detailAgreementIds.Contains(a.Id));
            }

            var relatedQuery =
                from a in agreements
                join d in userDetails on a.Id equals d.DividedAgreementId into gj
                from d in gj.DefaultIfEmpty()
                where (dto.IncludeParticipation && d != null) || (dto.IncludeOwned && a.CreatorId == targetUserId)
                select new
                {
                    Agreement = a,
                    IsParticipant = d != null,
                    IsOwner = a.CreatorId == targetUserId,
                    MyRatio = d != null ? (decimal?)d.Ratio : (decimal?)null
                };

            var total = await relatedQuery.CountAsync();

            var page = dto.Page <= 0 ? 1 : dto.Page;
            var limit = dto.Limit <= 0 ? 10 : dto.Limit;

            var list = await relatedQuery
                // 二者皆是时优先创作者，其次按创建时间倒序
                .OrderByDescending(x => x.IsOwner)
                .ThenByDescending(x => x.Agreement.CreationTime)
                .Skip((page - 1) * limit)
                .Take(limit)
                .Select(x => new DividedAgreementUserViewDto
                {
                    Id = x.Agreement.Id,
                    AgreementCode = x.Agreement.AgreementCode,
                    AgreementName = x.Agreement.AgreementName,
                    ParentAgreementId = x.Agreement.ParentAgreementId,
                    CreationTime = x.Agreement.CreationTime,
                    MerchantId = x.Agreement.MerchantId,
                    EnableStatus = x.Agreement.EnableStatus,
                    ActivationStatus = x.Agreement.ActivationStatus,
                    StartTime = x.Agreement.StartTime,
                    EndTime = x.Agreement.EndTime,
                    Relation = x.IsOwner ? "Owner" : "Participant",
                    MyRatio = x.IsParticipant ? x.MyRatio : (decimal?)null
                })
                .ToListAsync();

            return GetResult(1, data: new { data = list, total });
        }

        /// <summary>
        /// 获取分账协议详情列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedAgreementDetailListAsync(string dividedAgreementId)
        {
            var data = await _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => dividedAgreementId == d.DividedAgreementId,
                d => d.CreationTime, false).Select(d => new DividedAgreementDetailRequestDto
                {
                    Id = d.Id,
                    DividedAgreementId = d.DividedAgreementId,
                    CreationTime = d.CreationTime,
                    Ratio = d.Ratio,
                    UserId = d.UserId,
                    IsMasterAccount = d.IsMasterAccount,
                    ActivationStatus = d.ActivationStatus,
                    UserRoleId = d.UserRoleId,
                }).ToListAsync();

            foreach (var item in data)
            {
                var userRole = await _dividedIOC._sysUserRoleEFCore.QueryAll(d => d.Id == item.UserRoleId).FirstOrDefaultAsync();
                var user = await _dividedIOC._sysUserEFCore.QueryAll(d => d.Id == item.UserId).FirstOrDefaultAsync();
                item.UserPhone = user?.Phone;
                item.UserName = userRole?.Name?? user?.Name;
            }

            return GetResult(1, data: data);
        }

        /// <summary>
        /// 新增分账协议详情
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddDividedAgreementDetailAsync(DividedAgreementDetailRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                //var details = await _dividedIOC._dividedAgreementDetailEFCore
                //.QueryAll(d => d.DividedAgreementId == dto.DividedAgreementId)
                //.ToListAsync();

                //if (details.Any(d => d.UserId == dto.UserId))
                //{
                //    return GetResult(message: "该用户已存在于当前分账协议，请勿重复添加！");
                //}

                //// 查找主账户
                //var masterAccount = details.FirstOrDefault(d => d.IsMasterAccount);
                //if (masterAccount == null)
                //{
                //    return GetResult(message: "未找到主账户，无法添加分账明细");
                //}

                //// 计算当前总比例（不包含新添加的）
                //var currentTotalRatio = details.Sum(d => d.Ratio);

                //// 验证新比例是否合法
                //if (dto.Ratio <= 0 || dto.Ratio > 1 - currentTotalRatio + masterAccount.Ratio)
                //{
                //    return GetResult(message: "分账比例超出范围");
                //}

                //// 调整主账户比例 = 1 - 其他账户总和
                //masterAccount.Ratio = 1 - (currentTotalRatio - masterAccount.Ratio + dto.Ratio);
                //await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(masterAccount); 

                // 创建新的分账明细
                DividedAgreementDetail dividedAgreementDetail = new DividedAgreementDetail()
                {
                    Id = Config.GUID(),
                    DividedAgreementId = dto.DividedAgreementId,
                    Ratio = dto.Ratio,
                    UserId = dto.UserId,
                    CreationTime = DateTime.Now,
                    IsMasterAccount = (bool)dto.IsMasterAccount,//数据库默认为false
                    ActivationStatus = (int)dto.ActivationStatus,//数据库默认为0
                    UserRoleId = dto.UserRoleId,
                };

                await _dividedIOC._dividedAgreementDetailEFCore.AddAsync(dividedAgreementDetail);
                var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();

                if (result == 0)
                    return GetResult(message: "新增失败，请稍后重试！");

                scope.Complete();
                return GetResult(result, data: dividedAgreementDetail.Id);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 删除分账协议详情
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> DeleteDividedAgreementDetailAsync(DividedAgreementDetailRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                var detailsToDelete = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => dto.Ids.Contains(d.Id))
                    .ToListAsync();

                if (!detailsToDelete.Any())
                {
                    return GetResult(message: "参数错误");
                }

                // 检查是否包含主账户
                var masterAccountToDelete = detailsToDelete.FirstOrDefault(d => d.IsMasterAccount);
                if (masterAccountToDelete != null)
                {
                    return GetResult(message: "不能删除主账户");
                }

                var dividedAgreementId = detailsToDelete.First().DividedAgreementId;

                // 获取当前分账协议的所有明细（包括即将删除的）
                var allDetails = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => d.DividedAgreementId == dividedAgreementId)
                    .ToListAsync();

                // 查找主账户
                var masterAccount = allDetails.FirstOrDefault(d => d.IsMasterAccount);
                if (masterAccount == null)
                {
                    return GetResult(message: "未找到主账户");
                }

                // 计算即将删除的非主账户总比例
                var deletingRatio = detailsToDelete.Sum(d => d.Ratio);

                // 更新主账户比例 = 原比例 + 删除的比例
                masterAccount.Ratio = Math.Min(1, (dynamic)masterAccount.Ratio + deletingRatio);
                await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(masterAccount);

                // 删除选中的明细
                await _dividedIOC._dividedAgreementDetailEFCore.DeleteRangeAsync(detailsToDelete);
                var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();

                if (result == 0)
                    return GetResult(message: "删除失败，请稍后重试！");

                scope.Complete();
                return GetResult(result);
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 编辑分账协议详情
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateDividedAgreementDetailAsync(DividedAgreementDetailRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required,
                    TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                // 查询待更新的分账明细
                var targetDetail = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => d.Id == dto.Id && d.UserId == dto.UserId)
                    .FirstOrDefaultAsync();

                if (targetDetail == null)
                {
                    return GetResult(message: "分账明细不存在");
                }

                // 获取分账协议下的所有明细
                var allDetails = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => d.DividedAgreementId == targetDetail.DividedAgreementId)
                    .ToListAsync();

                // 查找主账户
                var masterAccount = allDetails.FirstOrDefault(d => d.IsMasterAccount);
                if (masterAccount == null)
                {
                    return GetResult(message: "未找到主账户");
                }

                // 禁止修改主账户状态
                if (dto.IsMasterAccount && dto.IsMasterAccount != targetDetail.IsMasterAccount)
                {
                    return GetResult(message: "不能修改主账户状态");
                }

                // 计算其他账户总比例（不包含待更新的账户）
                var otherAccountsRatio = allDetails
                    .Where(d => d.Id != targetDetail.Id)
                    .Sum(d => d.Ratio);

                // 如果更新的是非主账户，验证新比例是否合法
                if (!targetDetail.IsMasterAccount)
                {
                    // 新比例不能超过 1 - 其他账户总比例
                    if (dto.Ratio > 1 - otherAccountsRatio)
                    {
                        return GetResult(message: "分账比例超出范围");
                    }

                    // 计算比例变化量
                    var ratioDelta = dto.Ratio - targetDetail.Ratio;

                    // 更新主账户比例 = 原比例 - 变化量
                    masterAccount.Ratio = Math.Max(0, (dynamic)masterAccount.Ratio - ratioDelta);

                    // 更新主账户
                    await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(masterAccount);
                }
                else
                {
                    // 如果更新的是主账户，强制设置为 1
                    if (Math.Abs((dynamic)dto.Ratio - 1) > 0.0001)
                    {
                        return GetResult(message: "主账户比例必须为 1");
                    }
                }

                // 更新目标明细
                targetDetail.UserId = dto.UserId;
                targetDetail.Ratio = dto.Ratio;
                await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(targetDetail);
                var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();

                scope.Complete();
                return GetResult(result);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        /// <summary>
        /// 批量修改分账协议详情记录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateDividedAgreementDetailsAsync(List<DividedAgreementDetailRequestDto> dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                foreach (var item in dto)
                {
                    var targetDetail = await _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => d.Id == item.Id/* && d.UserId == item.UserId*/).FirstOrDefaultAsync();
                    //targetDetail.UserId = item.UserId;
                    targetDetail.Ratio = item.Ratio;

                    await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(targetDetail);
                }

                var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();

                if (result == 0)
                    return GetResult(message: "修改失败，请稍后重试！");

                scope.Complete();
                return GetResult(result);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 确认分账协议详情
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> ConfirmDividedAgreementDetailAsync(DividedAgreementDetailRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                //var dividedAgreementDetail = await _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => d.Id == dto.Id && d.Phone == dto.UserPhone).FirstOrDefaultAsync();
                //dividedAgreementDetail.ActivationStatus = 1;

                //var dividedAgreement = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dividedAgreementDetail.DividedAgreementId).FirstOrDefaultAsync();

                //var dividedAgreementDetails = await _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => d.DividedAgreementId == dividedAgreement.Id).ToListAsync();

                //int index = 0;
                //foreach (var item in dividedAgreementDetails)
                //{
                //    if (dividedAgreementDetail.Id == item.Id)
                //        continue;
                //    if (item.ActivationStatus == 1)
                //        index++;
                //}
                //if (index == dividedAgreementDetails.Count() - 1)
                //    dividedAgreement.ActivationStatus = 1;

                //await _dividedIOC._dividedAgreementDetailEFCore.UpdateAsync(dividedAgreementDetail);
                //await _dividedIOC._dividedAgreementEFCore.UpdateAsync(dividedAgreement);

                //var result = await _dividedIOC._dividedAgreementDetailEFCore.SaveChangesAsync();
                //if (result == 0)
                //    return GetResult(message: "确认失败，请稍后重试！");

                scope.Complete();
                return GetResult(1);
            }
            catch (Exception)
            {

                throw;
            }

        }

        /// <summary>
        /// 校验协议有效性
        /// </summary>
        /// <param name="a"></param>
        /// <param name="now"></param>
        /// <returns></returns>
        public static bool IsAgreementEffective(DividedAgreement a, DateTime now)
        {
            if (a == null) return false;
            return a.IsDeleted == false
                   && a.EnableStatus == 1
                   && a.ActivationStatus == 1
                   && now >= a.StartTime
                   && (!a.EndTime.HasValue || now <= a.EndTime.Value);
        }

        /// <summary>
        /// 成环/可达性校验：防止通过 SubAgreementId 形成循环结构，导致分账展开不完整
        /// </summary>
        /// <param name="startAgreementId"></param>
        /// <param name="targetAgreementId"></param>
        /// <returns></returns>
        private async Task<bool> IsReachableViaSubAgreementAsync(string startAgreementId, string targetAgreementId)
        {
            if (string.Equals(startAgreementId, targetAgreementId, StringComparison.OrdinalIgnoreCase))
                return true;

            var visited = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            var queue = new Queue<string>();
            visited.Add(startAgreementId);
            queue.Enqueue(startAgreementId);

            while (queue.Count > 0)
            {
                var current = queue.Dequeue();

                var children = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => d.DividedAgreementId == current && !string.IsNullOrEmpty(d.SubAgreementId))
                    .Select(d => d.SubAgreementId!)
                    .Distinct()
                    .ToListAsync();

                foreach (var child in children)
                {
                    if (child == null)
                        continue;

                    if (string.Equals(child, targetAgreementId, StringComparison.OrdinalIgnoreCase))
                        return true;

                    if (visited.Add(child))
                        queue.Enqueue(child);
                }
            }

            return false;
        }

        /// <summary>
        /// 检查嵌套分账协议配置是否陷入死循环
        /// </summary>
        /// <param name="parentAgreementId"></param>
        /// <param name="childAgreementId"></param>
        /// <returns></returns>
        private async Task<bool> WouldCreateCycleWhenBindingAsync(string parentAgreementId, string childAgreementId)
        {
            if (string.Equals(parentAgreementId, childAgreementId, StringComparison.OrdinalIgnoreCase))
                return true;

            return await IsReachableViaSubAgreementAsync(childAgreementId, parentAgreementId);
        }

        /// <summary>
        /// 校验是否已有父协议
        /// </summary>
        /// <param name="childAgreementId"></param>
        /// <returns></returns>
        private async Task<string?> FindExistingParentAgreementIdAsync(string childAgreementId)
        {
            var existingParentId = await _dividedIOC._dividedAgreementDetailEFCore
                .QueryAll(d => d.SubAgreementId == childAgreementId)
                .Select(d => d.DividedAgreementId)
                .FirstOrDefaultAsync();

            return string.IsNullOrEmpty(existingParentId) ? null : existingParentId;
        }

        /// <summary>
        /// 递归展开协议，得到所有“叶子接收人”的路径与连乘比例
        /// </summary>
        /// <param name="agreementId"></param>
        /// <param name="parentRatio"></param>
        /// <param name="path"></param>
        /// <param name="visiting"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        private async Task<List<LeafSplit>> ExpandAgreementSplitsRecursive(
            string agreementId,
            decimal parentRatio,
            List<PathNode> path,
            HashSet<string> visiting,
            Dictionary<string, List<DividedAgreementDetail>> cache,
            DateTime referenceTime)
        {
            var result = new List<LeafSplit>();

            if (visiting.Contains(agreementId))
            {
                // 检测到环，跳过该分支（也可写错误日志）
                return result;
            }

            visiting.Add(agreementId);

            // —— 协议有效性校验，失败则剪枝（按订单参考时间） ——
            var agreement = await _dividedIOC._dividedAgreementEFCore
                .QueryAll(d => d.Id == agreementId)
                .FirstOrDefaultAsync();
            bool effective = agreement != null
                && agreement.IsDeleted == false
                && agreement.EnableStatus == 1
                && agreement.ActivationStatus == 1
                && referenceTime >= agreement.StartTime
                && (!agreement.EndTime.HasValue || referenceTime <= agreement.EndTime.Value);

            if (!effective)
            {
                visiting.Remove(agreementId);
                return result;
            }
            // —— 协议有效性校验，失败则剪枝 ——

            List<DividedAgreementDetail> details;
            if (cache.TryGetValue(agreementId, out var cached))
            {
                details = cached
                    .OrderBy(d => d.UserId)
                    .ToList();
            }
            else
            {
                details = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => d.DividedAgreementId == agreementId)
                    .OrderBy(d => d.UserId)
                    .ToListAsync();
                cache[agreementId] = details;
            }

            foreach (var d in details)
            {
                var step = new PathNode { AgreementId = agreementId, UserId = d.UserId!, Ratio = (decimal)d.Ratio };
                var newPath = new List<PathNode>(path) { step };
                var nextRatio = parentRatio * (decimal)d.Ratio;

                if (!string.IsNullOrEmpty(d.SubAgreementId))
                {
                    // 下钻子协议（按参考时间继续）
                    var childSplits = await ExpandAgreementSplitsRecursive(
                        d.SubAgreementId!, nextRatio, newPath, visiting, cache, referenceTime);
                    result.AddRange(childSplits);
                }
                else
                {
                    // 叶子接收人
                    result.Add(new LeafSplit
                    {
                        LeafUserId = d.UserId!,
                        RatioProduct = nextRatio,
                        LayerAgreementId = agreementId,
                        Path = newPath
                    });
                }
            }

            visiting.Remove(agreementId);
            return result;
        }

        /// <summary>
        /// 新增分账记录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddDividedRecordAsync()
        {
            try
            {
                // 预取订单（协议不为空、未分账、已结算）
                var orders = await _dividedIOC._orderEFCore
                    .QueryAll(d => !string.IsNullOrEmpty(d.DividedAgreementId) && d.IsDivided == 0 && d.IsSettlement == 1)
                    .ToListAsync();

                if (orders.Count == 0)
                    return GetResult(1);

                // 预加载协议明细（按 UserId 固定顺序，降低死锁概率）
                var agreementIds = orders.Select(o => o.DividedAgreementId!).Distinct().ToList();
                var agreementDetails = await _dividedIOC._dividedAgreementDetailEFCore
                    .QueryAll(d => agreementIds.Contains(d.DividedAgreementId))
                    .ToListAsync();
                var detailsMap = agreementDetails
                    .GroupBy(d => d.DividedAgreementId)
                    .ToDictionary(g => g.Key, g => g.OrderBy(x => x.UserId).ToList());

                const int batchSize = 500;
                for (int i = 0; i < orders.Count; i += batchSize)
                {
                    var batch = orders.Skip(i).Take(batchSize).ToList();
                    await _unitOfWork.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);
                    try
                    {
                        var newRecords = new List<DividedRecord>();
                        var newDetails = new List<DividedRecordDetail>();
                        var updateOrderIds = new List<string>();

                        foreach (var order in batch)
                        {
                            if (string.IsNullOrEmpty(order.DividedAgreementId))
                                continue;

                            if (!detailsMap.TryGetValue(order.DividedAgreementId!, out var rootDetails) || rootDetails.Count == 0)
                                continue;

                            // 订单时刻口径参考时间
                            var referenceTime = order.CreationTime;

                            // 递归展开（不过滤明细）
                            var cache = new Dictionary<string, List<DividedAgreementDetail>>
                            {
                                { order.DividedAgreementId!, rootDetails
                                    .OrderBy(x => x.UserId)
                                    .ToList()
                                }
                            };

                            var leafSplits = await ExpandAgreementSplitsRecursive(
                                order.DividedAgreementId!,
                                1m,
                                new List<PathNode>(),
                                new HashSet<string>(),
                                cache,
                                referenceTime);

                            if (leafSplits.Count == 0)
                            {
                                await _logService.AddErrorLogAsync(new ErrorLogRequestDto
                                {
                                    Api = "AddDividedRecordAsync",
                                    Message = $"订单[{order.Id}]在参考时间无有效分账分支，跳过分账",
                                    Params = $"AgreementId={order.DividedAgreementId}, ReferenceTime={referenceTime:yyyy-MM-dd HH:mm:ss}",
                                    UserId = ""
                                });
                                continue;
                            }

                            // 生成分账主记录
                            string dividedRecordId = Config.GUID();
                            var dividedRecord = new DividedRecord()
                            {
                                Id = dividedRecordId,
                                RecordNo = Config.GUID(),
                                OrderId = order.Id,
                                MerchantId = order.MerchantId,
                                StoreId = order.StoreId,
                                CodeId = order.CodeId,
                                DividedAgreementId = order.DividedAgreementId!,
                                TotalDividedAmount = (long)order.SettlementAmount,
                                DividedDate = order.DividedDate,
                                CreationTime = DateTime.Now,
                            };
                            newRecords.Add(dividedRecord);

                            // 根主账户（参考时间有效的根层明细中为主账户者）
                            var rootMasterUserId = cache[order.DividedAgreementId!].FirstOrDefault(x => x.IsMasterAccount)?.UserId;

                            // 只扣一次总额（根主商户的待分账余额）
                            if (!string.IsNullOrEmpty(rootMasterUserId))
                            {
                                await _paymentService.AddAccountTransactionAsync(new AccountTransactionRequestDto
                                {
                                    UserId = rootMasterUserId!,
                                    Amount = -dividedRecord.TotalDividedAmount,
                                    OrderId = order.Id,
                                    TransactionType = 1,
                                    BalanceType = 5,
                                }, false);
                            }

                            // 生成分账详情与入账（根主商户入可提现，其他参与人入未结算）
                            foreach (var leaf in leafSplits)
                            {
                                var amount = (long)(dividedRecord.TotalDividedAmount * leaf.RatioProduct);
                                var isRootMaster = !string.IsNullOrEmpty(rootMasterUserId) && leaf.LeafUserId == rootMasterUserId;

                                var detail = new DividedRecordDetail()
                                {
                                    Id = Config.GUID(),
                                    DividedRecordId = dividedRecordId,
                                    UserId = leaf.LeafUserId,
                                    Ratio = leaf.RatioProduct,
                                    DividedAmount = amount,
                                    CreationTime = DateTime.Now,
                                    EntryTime = isRootMaster ? order.SettlementDate : null,
                                    IsEntry = isRootMaster,
                                    IsMasterAccount = isRootMaster,

                                    RootAgreementId = order.DividedAgreementId!,
                                    LayerAgreementId = leaf.LayerAgreementId,
                                    PathJson = System.Text.Json.JsonSerializer.Serialize(leaf.Path),
                                    PathDepth = leaf.Path.Count,
                                    PathAgreementCount = leaf.Path.Select(x => x.AgreementId).Distinct().Count(),
                                };
                                newDetails.Add(detail);

                                await _paymentService.AddAccountTransactionAsync(new AccountTransactionRequestDto
                                {
                                    UserId = detail.UserId,
                                    Amount = detail.DividedAmount,
                                    DividedRecordDetailId = detail.Id,
                                    TransactionType = 1,
                                    BalanceType = isRootMaster ? 3 : 4,
                                }, false);
                            }

                            updateOrderIds.Add(order.Id);
                        }

                        await _dividedIOC._dividedRecordEFCore.AddRangeAsync(newRecords);
                        await _dividedIOC._dividedRecordDetailEFCore.AddRangeAsync(newDetails);
                        // 批量更新订单的分账状态
                        DateTime now = DateTime.Now;
                        await _dividedIOC._orderEFCore
                            .QueryAll(o => updateOrderIds.Contains(o.Id))
                            .ExecuteUpdateAsync(s => s
                                .SetProperty(o => o.IsDivided, o => 1)
                                .SetProperty(o => o.DividedTime, o => now)
                                .SetProperty(o => o.LastModificationTime, o => now));

                        // 提交新增分账记录与详情
                        var affected = await _unitOfWork.SaveChangesAsync();
                        await _unitOfWork.CommitAsync();
                    }
                    catch (Exception ex)
                    {
                        await _unitOfWork.RollbackAsync();
                        await _logService.AddErrorLogAsync(new ErrorLogRequestDto
                        {
                            Api = "AddDividedRecordAsync",
                            Message = $"批次处理失败: {ex}",
                            Params = "",
                            UserId = ""
                        });
                        continue; // 继续下一个批次
                    }
                }

                return GetResult(1);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        /// <summary>
        /// 更新分账记录并结算
        /// </summary>
        /// <param name="dividedTime"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdateDividedRecordAsync(DateTime? dividedTime)
        {
            try
            {
                DateTime currentTime = (DateTime)(dividedTime == null ? DateTime.Now : dividedTime);
                DateTime dateOnly = currentTime.Date; // 只取日期部分（时间为 00:00:00）

                // 预加载当天分账记录并构建入账时间映射，避免循环内查询
                var dividedRecords = await _dividedIOC._dividedRecordEFCore
                    .QueryAll(d => d.DividedDate == dateOnly)
                    .AsNoTracking()
                    .ToListAsync();
                var entryTimeMap = dividedRecords.ToDictionary(d => d.Id, d => d.DividedDate);
                var dividedRecordIds = entryTimeMap.Keys.ToList();

                // 仅处理尚未入账的分账详情，并固定顺序减少死锁概率
                var dividedRecordDetails = await _dividedIOC._dividedRecordDetailEFCore
                    .QueryAll(d => dividedRecordIds.Contains(d.DividedRecordId) && d.IsEntry == false)
                    .OrderBy(d => d.UserId)
                    .ToListAsync();

                const int batchSize = 500; // 可按压测调整
                for (int i = 0; i < dividedRecordDetails.Count; i += batchSize)
                {
                    var batch = dividedRecordDetails.Skip(i).Take(batchSize).ToList();

                    try
                    {
                        await _unitOfWork.BeginTransactionAsync(System.Data.IsolationLevel.ReadCommitted);

                        foreach (var detail in batch)
                        {
                            // 设置入账标记与入账时间（取主记录分账日期）
                            detail.IsEntry = true;
                            detail.EntryTime = entryTimeMap[detail.DividedRecordId];

                            // 扣除未结算余额（余额类型：4）
                            await _paymentService.AddAccountTransactionAsync(new AccountTransactionRequestDto
                            {
                                UserId = detail.UserId,
                                Amount = -detail.DividedAmount,
                                DividedRecordDetailId = detail.Id,
                                TransactionType = 1,
                                BalanceType = 4
                            }, false);

                            // 转入可提现余额（余额类型：3）
                            await _paymentService.AddAccountTransactionAsync(new AccountTransactionRequestDto
                            {
                                UserId = detail.UserId,
                                Amount = detail.DividedAmount,
                                DividedRecordDetailId = detail.Id,
                                TransactionType = 1,
                                BalanceType = 3
                            }, false);
                        }

                        // 批量更新分账详情入账状态
                        await _dividedIOC._dividedRecordDetailEFCore.UpdateRangeAsync(batch);

                        // 统一提交（账户流水 + 分账详情），保证原子性
                        var affected = await _unitOfWork.SaveChangesAsync();
                        if (affected < batch.Count)
                        {
                            throw new Exception($"批次入账更新不完整，受影响行数：{affected}，批次大小：{batch.Count}");
                        }
                        await _unitOfWork.CommitAsync();
                    }
                    catch (Exception ex)
                    {
                        await _unitOfWork.RollbackAsync();
                        await _logService.AddErrorLogAsync(new ErrorLogRequestDto
                        {
                            Api = "UpdateDividedRecordAsync",
                            Message = $"批次处理失败: {ex}",
                            Params = $"batchStart={i}",
                            UserId = ""
                        });
                        continue; // 继续下一个批次
                    }
                }

                return GetResult(1);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取分账记录报表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedRecordReportAsync(DividedRecordQueryRequestDto dto)
        {
            var userId = _httpContextAccessor.HttpContext?.GetCurrentUserId() ?? string.Empty;
            if (string.IsNullOrEmpty(userId))
            {
                return GetResult(message: "用户未登录或未提供有效的用户ID，请稍后重试！");
            }

            var reportFormData = Config.GetDateRangeList((DateTime)dto.BeginTime, (DateTime)dto.EndTime).OrderByDescending(d => d.StartTime).ToList();

            List<DividedRecordSumResponseDto> data = new List<DividedRecordSumResponseDto>();
            foreach (var item in reportFormData)
            {
                if (string.IsNullOrEmpty(dto.MerchantId))
                {
                    var dividedRecordDetails = await _dividedIOC._dividedRecordDetailEFCore.QueryAll(d => d.UserId == userId
                    && (d.EntryTime >= item.StartTime && d.EntryTime <= item.EndTime))
                        .AsNoTracking()
                        .GroupBy(d => d.UserId)
                        .Select(d => new
                        {
                            TotalAmount = (long)d.Sum(x => (decimal?)x.DividedAmount ?? 0),
                            TotalCount = d.Select(x => x.DividedRecordId).Distinct().Count()
                        })
                        .FirstOrDefaultAsync() ?? new
                        {
                            TotalAmount = 0L,
                            TotalCount = 0,
                        };

                    var dividedRecordSum = new DividedRecordSumResponseDto
                    {
                        QueryDate = item.StartTime.Date,
                        TotalAmount = dividedRecordDetails.TotalAmount,
                        TotalCount = dividedRecordDetails.TotalCount,
                        //TotalAmount = dividedRecordDetails.Sum(d => d.DividedAmount),
                        //TotalCount = dividedRecordDetails.Count(),
                    };

                    data.Add(dividedRecordSum);
                }
                else
                {
                    var dividedRecord = await _dividedIOC._dividedRecordEFCore.QueryAll(d => d.MerchantId == dto.MerchantId
                    && (d.DividedDate >= item.StartTime && d.DividedDate <= item.EndTime))
                        .AsNoTracking()
                        .GroupBy(d => d.MerchantId)
                        .Select(d => new
                        {
                            TotalAmount = (long)d.Sum(x => (decimal?)x.TotalDividedAmount ?? 0),
                            TotalCount = d.Count()
                        })
                        .FirstOrDefaultAsync() ?? new
                        {
                            TotalAmount = 0L,
                            TotalCount = 0,
                        };

                    var dividedRecordSum = new DividedRecordSumResponseDto
                    {
                        QueryDate = item.StartTime.Date,
                        TotalAmount = dividedRecord.TotalAmount,
                        TotalCount = dividedRecord.TotalCount,
                    };

                    data.Add(dividedRecordSum);
                }
            }

            return GetResult(1, data: data);
        }

        /// <summary>
        /// 获取用户分账记录列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedRecordListAsync(DividedRecordQueryRequestDto dto)
        {
            var userId = _httpContextAccessor.HttpContext?.GetCurrentUserId() ?? string.Empty;
            if (string.IsNullOrEmpty(userId))
            {
                return GetResult(message: "用户未登录或未提供有效的用户ID，请稍后重试！");
            }

            //这里按UserId和DividedRecordId去重汇总DividedAmount的值
            // var dividedRecordDetails = await _dividedIOC._dividedRecordDetailEFCore.QueryAll(out int total, dto.Page, dto.Limit,
            //     d => d.UserId == userId && (d.EntryTime >= dto.BeginTime && d.EntryTime <= dto.EndTime),
            //     d => d.EntryTime, false).ToListAsync();

            // 按 UserId + DividedRecordId 分组聚合，求和 DividedAmount，并按最大 EntryTime 排序分页
            var baseQuery = _dividedIOC._dividedRecordDetailEFCore
                .QueryAll(d => d.UserId == userId
                               && d.EntryTime >= dto.BeginTime
                               && d.EntryTime <= dto.EndTime
                               /* 如需仅统计已入账，可启用以下条件 */
                               && d.IsEntry == true);//.OrderByDescending(x => x.CreationTime);

            // 总数为分组后的组数
            int total = await baseQuery
                .AsNoTracking()
                .GroupBy(d => new { d.UserId, d.DividedRecordId })
                .CountAsync();

            var aggregated = await baseQuery
                .AsNoTracking()
                .GroupBy(d => new { d.UserId, d.DividedRecordId })
                .Select(g => new
                {
                    g.Key.DividedRecordId,
                    SumAmount = g.Sum(x => x.DividedAmount),
                    MaxEntryTime = g.Max(x => x.EntryTime),
                })
                .OrderByDescending(x => x.MaxEntryTime)
                .Skip((dto.Page - 1) * dto.Limit)
                .Take(dto.Limit)
                .ToListAsync();


            List<DividedRecordResponseDto> data = new List<DividedRecordResponseDto>();
            foreach (var item in aggregated)
            {
                var dividedRecord = await _dividedIOC._dividedRecordEFCore.QueryAll(d => d.Id == item.DividedRecordId).FirstOrDefaultAsync();
                var dividedAgreement = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dividedRecord.DividedAgreementId).FirstOrDefaultAsync();
                data.Add(new DividedRecordResponseDto
                {
                    Id = dividedRecord.Id,
                    RecordNo = dividedRecord.RecordNo,
                    OrderId = dividedRecord.OrderId,
                    CodeId = dividedRecord.CodeId,
                    DividedAgreementId = dividedRecord.DividedAgreementId,
                    TotalDividedAmount = dividedRecord.TotalDividedAmount,
                    DividedDate = dividedRecord.DividedDate,
                    MerchantId = dividedRecord.MerchantId,
                    StoreId = dividedRecord.StoreId,
                    CreationTime = dividedRecord.CreationTime,
                    UserDividedAmount = item.SumAmount,//dividedRecordDetail.DividedAmount,
                    MaxEntryTime = item.MaxEntryTime,
                    DividedAgreementName = dividedAgreement.AgreementName
                });
            }

            data = data.OrderByDescending(x => x.CreationTime).ToList();
            return GetResult(1, data: new
            {
                total,
                data
            });
        }

        /// <summary>
        /// 获取商户分账记录列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetMerchantDividedRecordListAsync(DividedRecordQueryRequestDto dto)
        {
            var data = await _dividedIOC._dividedRecordEFCore.QueryAll(out int total, dto.Page, dto.Limit,
                d => (string.IsNullOrEmpty(dto.MerchantId) || d.MerchantId.Contains(dto.MerchantId))
                && (string.IsNullOrEmpty(dto.CodeId) || d.CodeId.Contains(dto.CodeId))
                && (string.IsNullOrEmpty(dto.DividedAgreementId) || d.DividedAgreementId.Contains(dto.DividedAgreementId))
                && d.DividedDate == dto.DividedDate,
                d => d.CreationTime, false).Select(d => new DividedRecordResponseDto
                {
                    Id = d.Id,
                    RecordNo = d.RecordNo,
                    OrderId = d.OrderId,
                    CodeId = d.CodeId,
                    DividedAgreementId = d.DividedAgreementId,
                    TotalDividedAmount = d.TotalDividedAmount,
                    DividedDate = d.DividedDate,
                    MerchantId = d.MerchantId,
                    StoreId = d.StoreId,
                    CreationTime = d.CreationTime,

                }).OrderByDescending(x => x.CreationTime).ToListAsync();

            foreach (var dividedRecord in data)
            {
                var dividedAgreement = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dividedRecord.DividedAgreementId).FirstOrDefaultAsync();
                dividedRecord.DividedAgreementName = dividedAgreement?.AgreementName;
            }
            return GetResult(1, data: new
            {
                total,
                data
            });
        }

        /// <summary>
        /// 获取用户分账记录详情树状图
        /// </summary>
        /// <param name="dividedRecordId">分账记录ID</param>
        /// <returns>返回当前用户参与的所有协议层级的根节点数组</returns>
        public async Task<ApiResult> GetDividedRecordTreeForUserAsync(string dividedRecordId)
        {
            var userId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
            if (string.IsNullOrEmpty(userId))
                return GetResult(message: "用户未登录或未提供有效的用户ID");

            var record = await _dividedIOC._dividedRecordEFCore
                .QueryAll(d => d.Id == dividedRecordId)
                .FirstOrDefaultAsync();
            if (record == null)
                return GetResult(message: "分账记录不存在");

            if (string.IsNullOrEmpty(record.DividedAgreementId))
                return GetResult(message: "分账记录缺少根协议ID");

            // 汇总 PathJson：静态比例 + 子层关系（edgeMap）
            var detailPaths = await _dividedIOC._dividedRecordDetailEFCore
                .QueryAll(d => d.DividedRecordId == record.Id)
                .Select(d => d.PathJson)
                .ToListAsync();

            var ratioMap = new Dictionary<string, decimal>(StringComparer.Ordinal);
            var edgeMap = new Dictionary<string, string>(StringComparer.Ordinal);
            foreach (var pathJson in detailPaths)
            {
                var path = System.Text.Json.JsonSerializer.Deserialize<List<PathNode>>(pathJson ?? "[]") ?? new List<PathNode>();
                for (int i = 0; i < path.Count; i++)
                {
                    var step = path[i];
                    ratioMap[$"{step.AgreementId}|{step.UserId}"] = step.Ratio;
                    if (i < path.Count - 1)
                    {
                        var nextAgreementId = path[i + 1].AgreementId;
                        if (!string.IsNullOrEmpty(nextAgreementId))
                        {
                            edgeMap[$"{step.AgreementId}|{step.UserId}"] = nextAgreementId;
                        }
                    }
                }
            }

            // 获取当前用户参与的所有分账路径
            var myDetails = await _dividedIOC._dividedRecordDetailEFCore
                .QueryAll(d => d.DividedRecordId == record.Id && d.UserId == userId)
                .ToListAsync();

            var treeArray = new List<AgreementTreeNode>();

            if (myDetails.Count > 0)
            {
                // 调试日志：记录myDetails的数量和基本信息
                Console.WriteLine($"[DEBUG] myDetails.Count: {myDetails.Count}");
                for (int idx = 0; idx < myDetails.Count; idx++)
                {
                    Console.WriteLine($"[DEBUG] myDetails[{idx}]: UserId={myDetails[idx].UserId}, DividedAmount={myDetails[idx].DividedAmount}");
                    Console.WriteLine($"[DEBUG] myDetails[{idx}].PathJson: {myDetails[idx].PathJson}");
                }

                // 第一步：收集所有路径并分析用户参与的层级
                var pathAnalysis = new List<(string pathKey, List<PathNode> pathNodes, List<int> userLevels)>();

                foreach (var detail in myDetails)
                {
                    var path = System.Text.Json.JsonSerializer.Deserialize<List<PathNode>>(detail.PathJson ?? "[]") ?? new List<PathNode>();
                    if (path.Count > 0)
                    {
                        // 构建路径标识（基于协议ID序列）
                        var pathKey = string.Join("->", path.Where(p => !string.IsNullOrEmpty(p.AgreementId)).Select(p => p.AgreementId));

                        // 找到用户参与的所有层级
                        var userLevels = new List<int>();
                        for (int i = 0; i < path.Count; i++)
                        {
                            if (path[i].UserId == userId)
                            {
                                userLevels.Add(i);
                            }
                        }

                        if (userLevels.Count > 0)
                        {
                            pathAnalysis.Add((pathKey, path, userLevels));
                            Console.WriteLine($"[DEBUG] 处理路径: {pathKey}");
                            Console.WriteLine($"[DEBUG] 用户参与层级: [{string.Join(", ", userLevels)}]");
                            Console.WriteLine($"[DEBUG] 路径详情: {string.Join(" | ", path.Select(p => $"UserId:{p.UserId}, AgreementId:{p.AgreementId}, Ratio:{p.Ratio}"))}");
                        }
                    }
                }

                // 第二步：全局分析所有路径，实现层级去重
                var allSegments = new List<(string pathKey, List<PathNode> pathNodes, List<int> segment, bool isContinuous)>();

                // 收集所有连续段和独立层级
                foreach (var (pathKey, pathNodes, userLevels) in pathAnalysis)
                {
                    var continuousSegments = FindContinuousSegments(userLevels);

                    Console.WriteLine($"[DEBUG] 路径 {pathKey} 的连续段分析:");
                    foreach (var segment in continuousSegments)
                    {
                        bool isContinuous = segment.Count > 1;
                        allSegments.Add((pathKey, pathNodes, segment, isContinuous));
                        Console.WriteLine($"[DEBUG]   {(isContinuous ? "连续段" : "独立层级")}: [{string.Join(", ", segment)}]");
                    }
                }

                // 按优先级排序：连续段优先，然后按段长度降序
                var sortedSegments = allSegments
                    .OrderByDescending(s => s.isContinuous ? 1 : 0)  // 连续段优先
                    .ThenByDescending(s => s.segment.Count)          // 长度优先
                    .ThenBy(s => s.segment[0])                       // 起始层级升序
                    .ToList();

                // 全局去重：跟踪已使用的层级
                var usedLevels = new HashSet<int>();
                var finalTreeNodes = new List<(string pathKey, List<PathNode> pathNodes, List<int> levels, string nodeType)>();

                Console.WriteLine($"[DEBUG] 开始全局去重处理:");

                foreach (var (pathKey, pathNodes, segment, isContinuous) in sortedSegments)
                {
                    // 检查该段是否与已使用层级重叠
                    bool hasOverlap = segment.Any(level => usedLevels.Contains(level));

                    if (!hasOverlap)
                    {
                        // 无重叠，可以使用该段
                        foreach (var level in segment)
                        {
                            usedLevels.Add(level);
                        }

                        string nodeType = isContinuous ? "continuous" : "single";
                        finalTreeNodes.Add((pathKey, pathNodes, segment, nodeType));

                        Console.WriteLine($"[DEBUG] 采用{nodeType}段: [{string.Join(", ", segment)}] from {pathKey}");
                    }
                    else
                    {
                        Console.WriteLine($"[DEBUG] 跳过重叠段: [{string.Join(", ", segment)}] from {pathKey}");
                    }
                }

                Console.WriteLine($"[DEBUG] 全局去重后最终树节点总数: {finalTreeNodes.Count}");

                // 第三步：为每个最终节点构建树
                foreach (var (pathKey, pathNodes, levels, nodeType) in finalTreeNodes)
                {
                    Console.WriteLine($"[DEBUG] 构建树节点: 路径={pathKey}, 层级=[{string.Join(", ", levels)}], 类型={nodeType}");

                    AgreementTreeNode? treeNode = null;

                    if (nodeType == "continuous")
                    {
                        // 连续链：从第一层开始构建
                        // 将PathNode转换为chain格式
                        var chain = new List<(string agreementId, int pathIndex, decimal accRatio)>();
                        decimal accRatio = 1m;

                        for (int i = 0; i < levels.Count; i++)
                        {
                            var levelIndex = levels[i];
                            accRatio *= pathNodes[levelIndex].Ratio;
                            chain.Add((pathNodes[levelIndex].AgreementId, levelIndex, accRatio));
                        }

                        Console.WriteLine($"[DEBUG] 构建连续链，共{chain.Count}层: {string.Join(" -> ", chain.Select(c => $"Level{c.pathIndex}({c.agreementId})"))}");

                        // 从第一层开始构建
                        treeNode = await BuildContinuousChainTreeAsync(chain, 0, record.TotalDividedAmount, ratioMap, edgeMap, userId);
                    }
                    else if (nodeType == "single")
                    {
                        // 单独层级：只构建该层级
                        var singleLevel = levels[0];
                        var agreementId = pathNodes[singleLevel].AgreementId;

                        // 计算到该层级的累积比例
                        decimal accRatio = 1m;
                        for (int i = 0; i <= singleLevel; i++)
                        {
                            accRatio *= pathNodes[i].Ratio;
                        }

                        Console.WriteLine($"[DEBUG] 构建单独层级 {singleLevel}: 协议={agreementId}, 累积比例={accRatio}");
                        treeNode = await BuildTreeFromLastLevelAsync(agreementId, accRatio, record.TotalDividedAmount, ratioMap, edgeMap);
                    }

                    if (treeNode != null)
                    {
                        treeArray.Add(treeNode);
                    }
                }

                Console.WriteLine($"[DEBUG] 最终树节点数量: {treeArray.Count}");
            }

            return GetResult(1, data: new
            {
                OrderId = record.OrderId,
                DividedRecordId = record.Id,
                RecordNo = record.RecordNo,
                TotalDividedAmount = record.TotalDividedAmount,
                UserDividedAmount = myDetails.Sum(d => d.DividedAmount),
                DividedDate = record.DividedDate,
                RootAgreementId = record.DividedAgreementId,
                Tree = treeArray // 返回数组，包含当前用户参与的所有协议层级
            });
        }


        /// <summary>
        /// 分析用户参与层级，找出连续段和独立层级
        /// </summary>
        /// <param name="userLevels">用户参与的层级列表</param>
        /// <returns>连续段列表，每个段包含连续的层级</returns>
        private List<List<int>> FindContinuousSegments(List<int> userLevels)
        {
            var segments = new List<List<int>>();
            if (userLevels.Count == 0) return segments;

            var sortedLevels = userLevels.OrderBy(x => x).ToList();
            var currentSegment = new List<int> { sortedLevels[0] };

            for (int i = 1; i < sortedLevels.Count; i++)
            {
                // 如果当前层级与前一个层级连续（相差1），加入当前段
                if (sortedLevels[i] == sortedLevels[i - 1] + 1)
                {
                    currentSegment.Add(sortedLevels[i]);
                }
                else
                {
                    // 不连续，结束当前段，开始新段
                    segments.Add(currentSegment);
                    currentSegment = new List<int> { sortedLevels[i] };
                }
            }

            // 添加最后一个段
            segments.Add(currentSegment);

            return segments;
        }

        /// <summary>
        /// 构建连续层级链的树结构（保持父子关系）
        /// </summary>
        /// <param name="chain">连续层级链</param>
        /// <param name="currentIndex">当前处理的链索引</param>
        /// <param name="totalAmount">总金额</param>
        /// <param name="ratioMap">比例映射</param>
        /// <param name="edgeMap">边映射</param>
        /// <param name="userId">当前用户ID</param>
        /// <returns>协议树节点</returns>
        private async Task<AgreementTreeNode> BuildContinuousChainTreeAsync(
            List<(string agreementId, int pathIndex, decimal accRatio)> chain,
            int currentIndex,
            long totalAmount,
            Dictionary<string, decimal> ratioMap,
            Dictionary<string, string> edgeMap,
            string userId)
        {
            var (agreementId, _, accRatio) = chain[currentIndex];

            var treeNode = await BuildAgreementTreeAsync(
                agreementId: agreementId,
                accRatio: accRatio,
                totalAmount: totalAmount,
                ratioMap: ratioMap,
                edgeMap: edgeMap
            );

            // 处理参与者
            var filteredParticipants = new List<ParticipantTreeNode>();
            foreach (var participant in treeNode.Participants)
            {
                var filteredParticipant = new ParticipantTreeNode
                {
                    UserId = participant.UserId,
                    UserName = participant.UserName,
                    Phone = participant.Phone,
                    Ratio = participant.Ratio,
                    Amount = participant.Amount,
                    HasSubAgreement = participant.HasSubAgreement,
                    SubAgreementId = participant.SubAgreementId,
                    HasOmittedSubLayers = false,
                    SubLayer = null
                };

                // 只有当前用户且还有下一层级时，才构建子层
                if (participant.UserId == userId && currentIndex < chain.Count - 1)
                {
                    var nextChainItem = chain[currentIndex + 1];
                    // 确保子协议ID匹配链中的下一个协议ID
                    if (!string.IsNullOrEmpty(participant.SubAgreementId) &&
                        participant.SubAgreementId == nextChainItem.agreementId)
                    {
                        filteredParticipant.SubLayer = await BuildContinuousChainTreeAsync(
                            chain, currentIndex + 1, totalAmount, ratioMap, edgeMap, userId);
                    }
                }
                // 对于非当前用户，如果有子协议但不在用户的连续链中，则不展开子层
                else if (participant.UserId != userId && participant.HasSubAgreement)
                {
                    filteredParticipant.HasOmittedSubLayers = true;
                }

                filteredParticipants.Add(filteredParticipant);
            }

            treeNode.Participants = filteredParticipants;
            return treeNode;
        }

        /// <summary>
        /// 构建从用户最后参与层级开始的树节点（单层，不展开子层）
        /// </summary>
        /// <param name="agreementId">协议ID</param>
        /// <param name="accRatio">累计比例</param>
        /// <param name="totalAmount">总金额</param>
        /// <param name="ratioMap">比例映射</param>
        /// <param name="edgeMap">边映射</param>
        /// <returns>协议树节点</returns>
        private async Task<AgreementTreeNode> BuildTreeFromLastLevelAsync(
            string agreementId,
            decimal accRatio,
            long totalAmount,
            Dictionary<string, decimal> ratioMap,
            Dictionary<string, string> edgeMap)
        {
            var agreement = await _dividedIOC._dividedAgreementEFCore
                .QueryAll(d => d.Id == agreementId)
                .FirstOrDefaultAsync();

            // 仍用 ratioMap 提取本层参与用户，保证只用"当次分账快照"的用户
            var recordUserIds = ratioMap
                .Where(kvp => kvp.Key.StartsWith(agreementId + "|", StringComparison.Ordinal))
                .Select(kvp => kvp.Key.Substring(agreementId.Length + 1))
                .Distinct()
                .ToList();

            // 仍可查协议详情用于枚举这些用户（不会包含快照之外的用户）
            var details = await _dividedIOC._dividedAgreementDetailEFCore
                .QueryAll(d => d.DividedAgreementId == agreementId && recordUserIds.Contains(d.UserId))
                .OrderBy(d => d.UserId)
                .ToListAsync();

            var userIds = details.Select(d => d.UserId!).Distinct().ToList();
            var users = await _dividedIOC._sysUserEFCore
                .QueryAll(u => userIds.Contains(u.Id))
                .Select(u => new { u.Id, u.Name, u.Phone })
                .ToListAsync();

            var participants = new List<ParticipantTreeNode>();

            foreach (var d in details)
            {
                var name = users.FirstOrDefault(u => u.Id == d.UserId)?.Name;
                var phone = users.FirstOrDefault(u => u.Id == d.UserId)?.Phone;

                var key = $"{agreementId}|{d.UserId}";
                var ratio = ratioMap.TryGetValue(key, out var r) ? r : 0m; // 非路径参与人比例为 0
                var amount = (long)(totalAmount * accRatio * ratio);

                // 使用 PathJson 快照推导子层协议关系，避免依赖 d.SubAgreementId 的最新值
                var hasChild = edgeMap.TryGetValue(key, out var childAgreementId);

                var node = new ParticipantTreeNode
                {
                    UserId = d.UserId!,
                    UserName = name,
                    Phone = phone,
                    Ratio = ratio,
                    Amount = amount,
                    HasSubAgreement = hasChild,
                    SubAgreementId = hasChild ? childAgreementId : null,
                    HasOmittedSubLayers = false,
                    SubLayer = null // 不展开子层，保持单层结构
                };

                participants.Add(node);
            }

            return new AgreementTreeNode
            {
                AgreementId = agreementId,
                AgreementName = agreement?.AgreementName,
                AccRatio = accRatio,
                AccAmount = (long)(totalAmount * accRatio),
                Participants = participants
            };
        }

        /// <summary>
        /// 获取完整分账树状图（使用 PathJson 静态比例）
        /// </summary>
        public async Task<ApiResult> GetDividedRecordFullTreeByOrderIdAsync(string? orderId, string? dividedRecordId)
        {
            // 查找该订单的最新分账记录
            var record = await _dividedIOC._dividedRecordEFCore
                .QueryAll(d => (string.IsNullOrEmpty(orderId) || d.OrderId == orderId) && (string.IsNullOrEmpty(dividedRecordId) || d.Id == dividedRecordId))
                .OrderByDescending(d => d.CreationTime)
                .FirstOrDefaultAsync();

            if (record == null)
                return GetResult(message: "未找到该订单的分账记录");

            if (string.IsNullOrEmpty(record.DividedAgreementId))
                return GetResult(message: "分账记录缺少根协议ID");

            // 汇总 PathJson 中的静态比例，键为 "AgreementId|UserId"
            var detailPaths = await _dividedIOC._dividedRecordDetailEFCore
                .QueryAll(d => d.DividedRecordId == record.Id)
                .Select(d => d.PathJson)
                .ToListAsync();

            var ratioMap = new Dictionary<string, decimal>(StringComparer.Ordinal);
            foreach (var pathJson in detailPaths)
            {
                var path = JsonSerializer.Deserialize<List<PathNode>>(pathJson ?? "[]") ?? new List<PathNode>();
                foreach (var step in path)
                {
                    ratioMap[$"{step.AgreementId}|{step.UserId}"] = step.Ratio;
                }
            }

            // 新增：依据 PathJson 快照推导“子层协议”关系，避免使用最新协议详情里的 SubAgreementId
            var edgeMap = new Dictionary<string, string>(StringComparer.Ordinal);
            foreach (var pathJson in detailPaths)
            {
                var path = JsonSerializer.Deserialize<List<PathNode>>(pathJson ?? "[]") ?? new List<PathNode>();
                for (int i = 0; i < path.Count - 1; i++)
                {
                    var cur = path[i];
                    var nextAgreementId = path[i + 1].AgreementId;
                    if (!string.IsNullOrEmpty(cur.AgreementId) && !string.IsNullOrEmpty(cur.UserId) && !string.IsNullOrEmpty(nextAgreementId))
                    {
                        edgeMap[$"{cur.AgreementId}|{cur.UserId}"] = nextAgreementId;
                    }
                }
            }

            // 构建完整树（递归），从根协议开始
            var root = await BuildAgreementTreeAsync(
                agreementId: record.DividedAgreementId!,
                accRatio: 1m,
                totalAmount: record.TotalDividedAmount,
                ratioMap: ratioMap,
                edgeMap: edgeMap
            );
            var treeArray = new List<AgreementTreeNode>();
            treeArray.Add(root);
            return GetResult(1, data: new
            {
                OrderId = record.OrderId,
                DividedRecordId = record.Id,
                RecordNo = record.RecordNo,
                TotalDividedAmount = record.TotalDividedAmount,
                DividedDate = record.DividedDate,
                RootAgreementId = record.DividedAgreementId,
                Tree = treeArray
            });
        }

        /// <summary>
        /// 递归构建某一层协议的树节点（使用 PathJson 静态比例）
        /// </summary>
        private async Task<AgreementTreeNode> BuildAgreementTreeAsync(string agreementId, decimal accRatio, long totalAmount, Dictionary<string, decimal> ratioMap, Dictionary<string, string> edgeMap)
        {
            var agreement = await _dividedIOC._dividedAgreementEFCore
                .QueryAll(d => d.Id == agreementId)
                .FirstOrDefaultAsync();

            // 仍用 ratioMap 提取本层参与用户，保证只用“当次分账快照”的用户
            var recordUserIds = ratioMap
                .Where(kvp => kvp.Key.StartsWith(agreementId + "|", StringComparison.Ordinal))
                .Select(kvp => kvp.Key.Substring(agreementId.Length + 1))
                .Distinct()
                .ToList();

            // 仍可查协议详情用于枚举这些用户（不会包含快照之外的用户）
            var details = await _dividedIOC._dividedAgreementDetailEFCore
                .QueryAll(d => d.DividedAgreementId == agreementId && recordUserIds.Contains(d.UserId))
                .OrderBy(d => d.UserId)
                .ToListAsync();

            var userIds = details.Select(d => d.UserId!).Distinct().ToList();
            var users = await _dividedIOC._sysUserEFCore
                .QueryAll(u => userIds.Contains(u.Id))
                .Select(u => new { u.Id, u.Name, u.Phone })
                .ToListAsync();

            var participants = new List<ParticipantTreeNode>();

            foreach (var d in details)
            {
                var name = users.FirstOrDefault(u => u.Id == d.UserId)?.Name;
                var phone = users.FirstOrDefault(u => u.Id == d.UserId)?.Phone;

                var key = $"{agreementId}|{d.UserId}";
                var ratio = ratioMap.TryGetValue(key, out var r) ? r : 0m; // 非路径参与人比例为 0
                var amount = (long)(totalAmount * accRatio * ratio);

                // 使用 PathJson 快照推导子层协议关系，避免依赖 d.SubAgreementId 的最新值
                var hasChild = edgeMap.TryGetValue(key, out var childAgreementId);

                var node = new ParticipantTreeNode
                {
                    UserId = d.UserId!,
                    UserName = name,
                    Phone = phone,
                    Ratio = ratio,
                    Amount = amount,
                    HasSubAgreement = hasChild,
                    SubAgreementId = hasChild ? childAgreementId : null
                };

                // 递归子层，使用快照中的 childAgreementId
                if (hasChild && !string.IsNullOrEmpty(childAgreementId))
                {
                    node.SubLayer = await BuildAgreementTreeAsync(childAgreementId!, accRatio * ratio, totalAmount, ratioMap, edgeMap);
                }

                participants.Add(node);
            }

            return new AgreementTreeNode
            {
                AgreementId = agreementId,
                AgreementName = agreement?.AgreementName,
                AccRatio = accRatio,
                AccAmount = (long)(totalAmount * accRatio),
                Participants = participants
            };
        }

        /// <summary>
        /// 获取分账记录根层详情
        /// </summary>
        /// <param name="dividedRecordId"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedRecordRootLayerAsync(string dividedRecordId)
        {
            // 查记录
            var record = await _dividedIOC._dividedRecordEFCore
        .QueryAll(d => d.Id == dividedRecordId)
        .FirstOrDefaultAsync();
            if (record == null)
                return GetResult(message: "分账记录不存在");

            // 直接使用记录上的根协议ID
            if (string.IsNullOrEmpty(record.DividedAgreementId))
                return GetResult(message: "分账记录缺少根协议ID");

            // 根层协议与参与人明细
            var agreement = await _dividedIOC._dividedAgreementEFCore
                .QueryAll(d => d.Id == record.DividedAgreementId)
                .FirstOrDefaultAsync();

            var details = await _dividedIOC._dividedAgreementDetailEFCore
                .QueryAll(d => d.DividedAgreementId == record.DividedAgreementId)
                .OrderBy(d => d.UserId)
                .ToListAsync();

            var userIds = details.Select(d => d.UserId!).Distinct().ToList();
            var users = await _dividedIOC._sysUserEFCore
                .QueryAll(u => userIds.Contains(u.Id))
                .Select(u => new { u.Id, u.Name, u.Phone })
                .ToListAsync();

            // 统一为 AgreementTreeNode + ParticipantTreeNode 结构（与 GetDividedRecordFullTreeByOrderIdAsync 一致）
            var participants = details.Select(d =>
            {
                var name = users.FirstOrDefault(u => u.Id == d.UserId)?.Name;
                var phone = users.FirstOrDefault(u => u.Id == d.UserId)?.Phone;
                var ratio = (decimal)d.Ratio;
                var amount = (long)(record.TotalDividedAmount * ratio);

                return new ParticipantTreeNode
                {
                    UserId = d.UserId!,
                    UserName = name,
                    Phone = phone,
                    Ratio = ratio,
                    Amount = amount,
                    HasSubAgreement = !string.IsNullOrEmpty(d.SubAgreementId),
                    SubAgreementId = d.SubAgreementId,
                    HasOmittedSubLayers = false,
                    SubLayer = null
                };
            }).ToList();

            var rootTree = new AgreementTreeNode
            {
                AgreementId = record.DividedAgreementId,
                AgreementName = agreement?.AgreementName,
                AccRatio = 1m,
                AccAmount = record.TotalDividedAmount,
                Participants = participants
            };
            var treeArray = new List<AgreementTreeNode>();
            treeArray.Add(rootTree);
            return GetResult(1, data: new
            {
                OrderId = record.OrderId,
                DividedRecordId = record.Id,
                RecordNo = record.RecordNo,
                TotalDividedAmount = record.TotalDividedAmount,
                DividedDate = record.DividedDate,
                RootAgreementId = record.DividedAgreementId,
                Tree = treeArray
            });
        }

        /// <summary>
        /// 获取分账记录详情列表
        /// </summary>
        /// <param name="dividedRecordId"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetDividedRecordDetailListAsync(string dividedRecordId)
        {
            var dividedRecord = await _dividedIOC._dividedRecordEFCore.QueryAll(d => d.Id == dividedRecordId).FirstOrDefaultAsync();
            if (dividedRecord == null)
            {
                return GetResult(message: "未找到对应的分账记录，请稍后重试！");
            }
            var dividedAgreement = await _dividedIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dividedRecord.DividedAgreementId).FirstOrDefaultAsync();
            if (dividedAgreement == null)
            {
                return GetResult(message: "未找到对应的分账协议，请稍后重试！");
            }

            var dividedRecordDetails = await _dividedIOC._dividedRecordDetailEFCore.QueryAll(
                d => (string.IsNullOrEmpty(dividedRecordId) || d.DividedRecordId.Contains(dividedRecordId)),
                d => d.CreationTime, false).Select(d => new DividedRecordDetailResponseDto()
                {
                    Id = d.Id,
                    DividedRecordId = d.DividedRecordId,
                    UserId = d.UserId,
                    Ratio = d.Ratio,
                    DividedAmount = d.DividedAmount,
                    CreationTime = d.CreationTime,
                    EntryTime = d.EntryTime,
                    IsEntry = d.IsEntry,
                    IsMasterAccount = d.IsMasterAccount,
                }).ToListAsync();

            foreach (var dividedRecordDetail in dividedRecordDetails)
            {
                var dividedAgreementDetail = await _dividedIOC._dividedAgreementDetailEFCore.QueryAll(d => d.DividedAgreementId == dividedAgreement.Id && d.UserId == dividedRecordDetail.UserId).FirstOrDefaultAsync();
                if (dividedAgreementDetail != null)
                    dividedRecordDetail.UserName = await _dividedIOC._sysUserRoleEFCore.QueryAll(d => d.Id == dividedAgreementDetail.UserRoleId).Select(d => d.Name).FirstOrDefaultAsync();
            }

            return GetResult(1, data: dividedRecordDetails);
        }
    }
}
